package org.midy.client;

import org.midy.infrastructure.tools.CloseHandler;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

public class AsyncEventHandler {
    private static final AtomicInteger async_thread_counter = new AtomicInteger(1);
    /**
     * 自定义的连接池(全局的)
     */
    private static final ConcurrentHashMap<String, AsyncEventHandler> socket_channel_map = new ConcurrentHashMap();

    private static final LinkedList<Thread> work_thread_list = new LinkedList();

    private Selector selector;

    private final String ip;

    private final int port;

    private SocketChannel socketChannel;

    public AsyncEventHandler(String ip, int port) {
        this.ip = ip;
        this.port = port;
    }

    public synchronized static AsyncEventHandler start(String ip, int port) {
        // 检查是否存在连接
        AsyncEventHandler clientAsyncEventExist = socket_channel_map.get(String.format("%s:%d", ip, port));
        if(clientAsyncEventExist != null) {
            return clientAsyncEventExist;
        }

        AsyncEventHandler clientAsyncEven = new AsyncEventHandler(ip,port);

        try {
            clientAsyncEven.selector = openSelector();
            clientAsyncEven.socketChannel = openSocket(ip, port);
            clientAsyncEven.socketChannel.register(clientAsyncEven.selector, SelectionKey.OP_CONNECT);
            startEventLoopExecutor(clientAsyncEven);
            socket_channel_map.put(String.format("%s:%d", ip, port), clientAsyncEven);
        } catch(Throwable t) {
            CloseHandler.closeSelector(clientAsyncEven.selector);
            CloseHandler.closeSocketChannel(clientAsyncEven.socketChannel);
            throw new RuntimeException("连接初始化失败", t);
        }

        return clientAsyncEven;
    }

    private static void startEventLoopExecutor(AsyncEventHandler clientAsyncEvent) {
        Thread work = new Thread(new Runnable() {
            @Override
            public void run() {
                final AsyncEventHandler bindAsyncEvenHandler = clientAsyncEvent;
                final Selector selector= bindAsyncEvenHandler.selector;
                try {
                    while (true) {
                        selector.select();
                        Set<SelectionKey> selectionKeys = selector.selectedKeys();// 去除无效key
                    }
                } catch (Exception e) {

                } finally {//线程退出的关闭所有应该关闭的资源和清空所有的缓存
                    Iterator<SelectionKey> selectionKeyIterator = selector.selectedKeys().iterator();
                    while (selectionKeyIterator.hasNext()) {
                        CloseHandler.closeSelectionKey(selectionKeyIterator.next());
                    }
                    CloseHandler.closeSelector(selector);
                }
            }
        }, String.format("async-work-%d", async_thread_counter.getAndIncrement()));
        work.setDaemon(true);
        work.start();
        work_thread_list.add(work);
    }

    private static Selector openSelector() {
        try {
            return Selector.open();
        } catch (IOException e) {
            throw new RuntimeException("Selector.open() 失败");
        }
    }

    private static SocketChannel openSocket(String ip, int port) {
        if(ip == null || port < 0) {
            throw new RuntimeException("非法的IP和PORT");
        }
        
        try {
            return SocketChannel.open(new InetSocketAddress(ip, port));
        } catch (Throwable t) {
            throw new RuntimeException("连接失败", t);
        }
    }
}
